/**
 * HTTP Server Module
 * Features:
 * - Supports GET/POST requests
 * - Supports file upload via raw body ('application/octet-stream') and multipart form data ('multipart/form-data').
 * - Supports file download
 * - Supports static html file service
 * - Multi-threading not supported, all functions should run in a single thread. For cross-thread communication, use dxEventbus to pass data
 * 
 * Usage:
 * - Simple WebServer
 * - Simple Web API Service
 */
import { httpserverClass } from './libvbar-m-dxhttpserver.so'

let server = null;
const httpserver = {}
httpserver.init = function () {
    if (!server) {
        server = new httpserverClass();
    }
}
/**
 * Route the HTTP request. A maximum of 100 routes can be registered.
 * @param {string} path - The path to route the request. Should start with '/'. 
 *                        Supports wildcard matching by ending with '/*'.
 * @param {function} callback - The callback function to handle the request
 * @param {object} callback.req - The request object
 * @param {string} callback.req.method - The HTTP method (GET, POST, etc.)
 * @param {string} callback.req.url - The request URL
 * @param {string} callback.req.query - The query string (e.g. "a=1&b=2")
 * @param {object} callback.req.headers - The request headers
 * @param {string} [callback.req.body] - The request body (only for specific Content-Type)
 * @param {function(string): boolean} callback.req.saveFile - Function to save uploaded file from raw request body. Returns true on success.
 * @param {function(string): object} callback.req.saveMultipartFile - Function to handle 'multipart/form-data' upload. It saves the file part to the specified path and returns other fields as an object.
 * @param {object} callback.res - The response object
 * @param {function} callback.res.send - Send response with body and headers,the header should be a object and the size should be < 512
 * @param {function} callback.res.sendFile - Send file as response
 * 
 * @example
 * // Basic usage 
 * httpserver.route('/hello', function(req, res) {
 *   res.send('Hello World', {'Content-Type': 'text/plain'});
 * });
 * 
 * @example
 * // Wildcard route to handle all requests under /api/
 * httpserver.route('/api/*', function(req, res) {
 *   // req.url will be the full URL, e.g., "/api/users/123"
 *   if (req.url.startsWith('/api/users/')) {
 *     const userId = req.url.substring(11);
 *     res.send(`User ID is ${userId}`);
 *   } else {
 *     res.send('Welcome to the API!');
 *   }
 * });
 * 
 * @example
 * // Handle file upload (raw body). Client should POST the file content directly.
 * // Example with curl:
 * // curl -X POST --data-binary "@/path/to/your/file.txt" \
 * //   -H "Content-Type: application/octet-stream" \
 * //   http://127.0.0.1:8080/upload
 * httpserver.route('/upload', function(req, res) {
 *   req.saveFile('/app/code/data/file_saved.txt');
 *   res.send('File saved');
 * });
 * 
 * @example
 * // Handle multipart/form-data upload.
 * // This saves the file part to the specified path and returns other form fields.
 * // Example with curl:
 * // curl -X POST -F "file1=@/path/to/your/file.bin" \
 * //   -F "user=JohnDoe" \
 * //   -F "timestamp=1678886400" \
 * //   http://127.0.0.1:8080/form-upload
 * httpserver.route('/form-upload', function(req, res) {
 *   const fields = req.saveMultipartFile('/app/code/data/uploaded_file.bin');
 *   // fields will be: { user: "JohnDoe", timestamp: "1678886400" }
 *   res.send(`File saved, user was ${fields.user}`);
 * });
 * 
 * @example
 * // Handle file download
 * httpserver.route('/download', function(req, res) {
 *   res.sendFile('/app/code/data/file.txt');
 * });
 */
httpserver.route = function (path, callback) {
    httpserver.init();

    // Wrap the user's callback in a try...catch block to handle uncaught exceptions
    const wrappedCallback = (req, res) => {
        try {
            callback(req, res);
        } catch (e) {
            try {
                res.send(JSON.stringify({
                    error: "Internal Server Error",
                    message: String(e)+"\n"+e.stack
                }), { "Content-Type": "application/json" });
            } catch (resError) {
            }
        }
    };

    server.route(path, wrappedCallback);
};
/**
 * Starts the HTTP server listening for connections. 
 * @param {number} port 
 */
httpserver.listen = function (port) {
    httpserver.init();
    server.listen(port);
}
/**
 * Loop the HTTP server
 */
httpserver.loop = function () {
    httpserver.init();
    server.loop();
}
/**
 * Serve static files
 * @param {string} path  The path to serve static files,should be start with '/'
 * @param {string} dir  The directory to serve static files,should be a absolute path start with '/app'
 */
httpserver.serveStatic = function (path, dir) {
    httpserver.init();
    if (!path) {
        path = '/';
    }
    if (!path.startsWith('/')) {
        path = '/' + path;
    }
    if (!path.endsWith('/')) {
        path = path + '/';
    }
    //path should be start with '/' and end with '/',or '/'
    server.serveStatic(path, dir);
}
/**
 * Deinitialize the server
 */
httpserver.deinit = function () {
    if (server) {
        server = null;
    }
}
/**
 * Get the native server object
 * @returns {Object} Native server object
 */
httpserver.getNative = function () {
    httpserver.init();
    return server;
}
export default httpserver;